{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "medical-utility",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-01T11:11:33.007278Z",
     "start_time": "2024-04-01T11:11:31.238684Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\SoftWare\\Code\\IDE\\Anaconda3\\envs\\torch_hwzhao\\lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22242e54",
   "metadata": {},
   "source": [
    "## PyTorch中创建张量"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8f212a0",
   "metadata": {},
   "source": [
    "### 直接创建\n",
    "\n",
    "`torch.tensor(data, dtype=None, device=None, requires_grad=False, pin_memory=False)`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "opening-boards",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-01T11:11:47.894291Z",
     "start_time": "2024-04-01T11:11:47.864562Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ndarray的数据类型： float64\n",
      "tensor([[1., 1., 1.],\n",
      "        [1., 1., 1.],\n",
      "        [1., 1., 1.]], dtype=torch.float64)\n"
     ]
    }
   ],
   "source": [
    "ndarray = np.ones((3, 3))\n",
    "print(\"ndarray的数据类型：\", ndarray.dtype)\n",
    "# 创建存放在 GPU 的数据\n",
    "# t = torch.tensor(ndarray, device='cuda')\n",
    "t= torch.tensor(ndarray)\n",
    "print(t)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "056a24f4",
   "metadata": {},
   "source": [
    "### 指定类型函数随机创建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "funny-complexity",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-01T11:13:26.435386Z",
     "start_time": "2024-04-01T11:13:26.428903Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[1.7035e-34, 0.0000e+00, 1.6143e-34],\n",
      "        [0.0000e+00, 7.0062e+22, 2.1715e-18]]) \n",
      " tensor([-1457705888,       32663], dtype=torch.int32) \n",
      " tensor([1, 2, 3, 4], dtype=torch.int32)\n"
     ]
    }
   ],
   "source": [
    "out_a = torch.FloatTensor(2,3)\n",
    "out_b = torch.IntTensor(2)\n",
    "out_c = torch.IntTensor([1,2,3,4])\n",
    "print(out_a,'\\n',out_b,'\\n',out_c)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00fcd423",
   "metadata": {},
   "source": [
    "### tensor和numpy array之间的相互转换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "16ba2b77d4e1a9d7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "修改tensor\n",
      "numpy array:  [[-1  2  3]\n",
      " [ 4  5  6]]\n",
      "tensor :  tensor([[-1,  2,  3],\n",
      "        [ 4,  5,  6]])\n"
     ]
    }
   ],
   "source": [
    "arr = np.array([[1, 2, 3], [4, 5, 6]])\n",
    "t = torch.from_numpy(arr)\n",
    "# 修改 tensor，array 也会被修改\n",
    "print(\"\\n修改tensor\")\n",
    "t[0, 0] = -1\n",
    "print(\"numpy array: \", arr)\n",
    "print(\"tensor : \", t)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6bc6370e",
   "metadata": {},
   "source": [
    "注意：torch.tensor创建得到的张量和原数据是不共享内存的，张量对应的变量是独立变量。  \n",
    "而torch.from_numpy()和torch.as_tensor()从numpy array创建得到的张量和原数据是共享内存的，张量对应的变量不是独立变量，修改numpy array会导致对应tensor的改变。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "empty-blocking",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[0.4110, 0.8827, 0.3000],\n",
      "        [0.3471, 0.5926, 0.5523]]) \n",
      " tensor([[1., 1., 1.],\n",
      "        [1., 1., 1.]]) \n",
      " tensor([[0., 0., 0.],\n",
      "        [0., 0., 0.]]) \n",
      " tensor([0, 2, 4, 6, 8])\n"
     ]
    }
   ],
   "source": [
    "# 常见的构造Tensor的函数\n",
    "k = torch.rand(2, 3) \n",
    "l = torch.ones(2, 3)\n",
    "m = torch.zeros(2, 3)\n",
    "n = torch.arange(0, 10, 2)\n",
    "print(k, '\\n', l, '\\n', m, '\\n', n)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f64f5cf34b8e58e",
   "metadata": {},
   "source": [
    "## PyTorch中tensor的常用方法"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f5fb30582b53f9c",
   "metadata": {},
   "source": [
    "### 查看tensor维度信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "characteristic-lighting",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([2, 3])\n",
      "torch.Size([2, 3])\n"
     ]
    }
   ],
   "source": [
    "# 查看tensor的维度信息（两种方式）\n",
    "out = torch.randn(2, 3)\n",
    "print(out.size())\n",
    "print(out.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0bc9bcf1b577198",
   "metadata": {},
   "source": [
    "### tensor.view()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "removed-lawrence",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-01T11:14:54.612689Z",
     "start_time": "2024-04-01T11:14:54.605419Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([4, 4])\n",
      "torch.Size([16])\n",
      "torch.Size([2, 8])\n",
      "torch.Size([2, 2, 4])\n"
     ]
    }
   ],
   "source": [
    "# 创建一个形状为 (4, 4) 的张量\n",
    "x = torch.randn(4, 4)\n",
    "print(x.size())  # 输出: torch.Size([4, 4])\n",
    "\n",
    "# 使用 torch.view 将 x 重塑为形状 (16,) 的一维张量\n",
    "y = x.view(16)\n",
    "print(y.size())  # 输出: torch.Size([16])\n",
    "\n",
    "# 使用 -1 自动计算维度大小，将 x 重塑为形状 (2, 8) 的二维张量\n",
    "z = x.view(2, -1)\n",
    "print(z.size())  # 输出: torch.Size([2, 8])\n",
    "\n",
    "# 也可以重塑为更高维度的张量，只要元素总数保持不变\n",
    "m = x.view(2, 2, 4)\n",
    "print(m.size())  # 输出: torch.Size([2, 2, 4])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "756bca264a7fd01f",
   "metadata": {},
   "source": [
    "### 广播机制"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "4a075afe1ee880e2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-01T11:15:23.460600Z",
     "start_time": "2024-04-01T11:15:23.452957Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[1, 2]])\n",
      "tensor([[1],\n",
      "        [2],\n",
      "        [3]])\n"
     ]
    }
   ],
   "source": [
    "x = torch.arange(1, 3).view(1, 2)\n",
    "print(x)\n",
    "y = torch.arange(1, 4).view(3, 1)\n",
    "print(y)\n",
    "# print(x + y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## tensor乘法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([3, 1])\n",
      "torch.Size([3, 2, 4])\n",
      "tensor([[[ 1,  1,  1,  1],\n",
      "         [ 2,  2,  2,  2]],\n",
      "\n",
      "        [[ 6,  6,  6,  6],\n",
      "         [ 8,  8,  8,  8]],\n",
      "\n",
      "        [[15, 15, 15, 15],\n",
      "         [18, 18, 18, 18]]])\n"
     ]
    }
   ],
   "source": [
    "weights = torch.tensor([[1],[2],[3]])\n",
    "input = torch.tensor([[[1,1,1,1],[2,2,2,2]],[[3,3,3,3],[4,4,4,4]],[[5,5,5,5],[6,6,6,6]]])\n",
    "print(weights.size())\n",
    "print(input.size())\n",
    "print(input* weights[:,0].unsqueeze(1).unsqueeze(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d9dd876c4bba7344",
   "metadata": {},
   "source": [
    "### CUDA中的tensor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "entire-farmer",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-01T11:16:10.560511Z",
     "start_time": "2024-04-01T11:16:09.233058Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[1.7848, 0.6444]], device='cuda:0')\n",
      "tensor([[1.7848, 0.6444]], dtype=torch.float64)\n"
     ]
    }
   ],
   "source": [
    "x = torch.randn(1,2)\n",
    "if torch.cuda.is_available():\n",
    "    device = torch.device(\"cuda\")          # cuda device对象\n",
    "    y = torch.ones_like(x, device=device)  # 创建一个在cuda上的tensor\n",
    "    x = x.to(device)                       # 使用方法把x转为cuda 的tensor\n",
    "    z = x + y\n",
    "    print(z)\n",
    "    print(z.to(\"cpu\", torch.double))       # .to方法也能够同时设置类型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "deadly-young",
   "metadata": {},
   "source": [
    "## 自动求导示例\n",
    "  \n",
    ">这里将通过一个简单的函数  $y=x_1+2*x_2$  来说明PyTorch自动求导的过程"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "prostate-local",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor(5., grad_fn=<AddBackward0>)\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "\n",
    "x1 = torch.tensor(1.0, requires_grad=True)\n",
    "x2 = torch.tensor(2.0, requires_grad=True)\n",
    "y = x1 + 2*x2\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "grand-appliance",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "# 首先查看每个变量是否需要求导\n",
    "print(x1.requires_grad)\n",
    "print(x2.requires_grad)\n",
    "print(y.requires_grad)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "virgin-parameter",
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'NoneType' object has no attribute 'data'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m/tmp/ipykernel_11770/1707027577.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# 查看每个变量导数大小。此时因为还没有反向传播，因此导数都不存在\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx1\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgrad\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgrad\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgrad\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'data'"
     ]
    }
   ],
   "source": [
    "# 查看每个变量导数大小。此时因为还没有反向传播，因此导数都不存在\n",
    "print(x1.grad.data)\n",
    "print(x2.grad.data)\n",
    "print(y.grad.data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "patient-carpet",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(1., requires_grad=True)"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "governing-arctic",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor(1.)\n",
      "tensor(2.)\n"
     ]
    }
   ],
   "source": [
    "## 反向传播后看导数大小\n",
    "y = x1 + 2*x2\n",
    "y.backward()\n",
    "print(x1.grad.data)\n",
    "print(x2.grad.data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "needed-harrison",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor(5.)\n",
      "tensor(10.)\n"
     ]
    }
   ],
   "source": [
    "# 导数是会累积的，重复运行相同命令，grad会增加\n",
    "y = x1 + 2*x2\n",
    "y.backward()\n",
    "print(x1.grad.data)\n",
    "print(x2.grad.data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "vocational-thesaurus",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 所以每次计算前需要清除当前导数值避免累积，这一功能可以通过pytorch的optimizer实现。后续会讲到"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "prostate-diagnosis",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 尝试，如果不允许求导，会出现什么情况？\n",
    "x1 = torch.tensor(1.0, requires_grad=False)\n",
    "x2 = torch.tensor(2.0, requires_grad=False)\n",
    "y = x1 + 2*x2\n",
    "y.backward()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "according-outdoors",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "promotional-gilbert",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "torch_hwzhao",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
